package com.alibaba.util;

import java.math.BigInteger;

public class SnowflakeIdGenerator {
    // 起始时间戳 (2020-01-01)
    private static final long twepoch = 1577836800000L;

    // 每部分的位数
    private static final long workerIdBits = 5L;
    private static final long datacenterIdBits = 5L;
    private static final long sequenceBits = 12L;

    // 每部分的最大值
    private static final long maxWorkerId = ~(-1L << workerIdBits);
    private static final long maxDatacenterId = ~(-1L << datacenterIdBits);

    // 左移位数
    private static final long workerIdShift = sequenceBits;
    private static final long datacenterIdShift = sequenceBits + workerIdBits;
    private static final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

    // 序列号掩码
    private static final long sequenceMask = ~(-1L << sequenceBits);

    private static long workerId = 1;
    private static long datacenterId = 1;
    private static long sequence = 0L;
    private static long lastTimestamp = -1L;

    public SnowflakeIdGenerator(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("workerId can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenterId can't be greater than %d or less than 0", maxDatacenterId));
        }
        SnowflakeIdGenerator.workerId = workerId;
        SnowflakeIdGenerator.datacenterId = datacenterId;
    }

    public static synchronized BigInteger nextId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        // 生成 ID，确保它不会超出 JavaScript 的最大整数安全范围
        long id = ((timestamp - twepoch) << timestampLeftShift) |
                (datacenterId << datacenterIdShift) |
                (workerId << workerIdShift) |
                sequence;

        // 截取高位部分以确保 ID 在安全范围内
        if (id > 9007199254740991L) { // 超出最大安全整数值
            id = id & 0x7FFFFFFFFFFFFFFFL; // 保证只取低 53 位
        }

        // 限制 ID 在 42 位以内，确保其不会超过 JavaScript number 范围
        id = id & 0x3FFFFFFFFFL;  // 限制为 42 位，适合 number 范围

        return BigInteger.valueOf(id); // 返回值为 BigInteger 类型，避免超出范围
    }

    protected static long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    protected static long timeGen() {
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            System.out.println(SnowflakeIdGenerator.nextId());
        }
    }
}